package com.winning.zjjh.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.winning.zjjh.entity.HeaderEntity;
import com.winning.zjjh.entity.RegCardEntity;
import com.winning.zjjh.entity.RequestEntity;
import com.winning.zjjh.entity.ServiceEnum;
import com.winning.zjjh.service.UDService;
import com.winning.zjjh.utils.JAXBUtils;
import com.winning.zjjh.utils.NetDataUtil;
import com.winning.zjjh.ws.MchisInterface;
import com.winning.zjjh.ws.MchisInterface_Service;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.parsers.DocumentBuilder;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @Author: xkh@winning.com.cn
 * @Desc: TODO
 * @Date: 2019-03-18 13:22
 **/
@Component(value = "udc")
public class UDController {

    private static Logger logger = LoggerFactory.getLogger(UDController.class);

    @Autowired
    private UDService udService;

    @Value("${zjjh.singleBatchSize}")
    private int singleSize;

    @Value("${zjjh.authKey}")
    private String authKey;

    @Value("${zjjh.singleBatchPages}")
    private int singleBatchPages;

    private MchisInterface_Service mchisInterface_service = new MchisInterface_Service();
    private MchisInterface mchisInterface = mchisInterface_service.getMchisInterfaceImplPort();

    private Map<String, String> records = new HashMap<String, String>();

    public void task(ServiceEnum serviceEnum) {
        String date = NetDataUtil.date(new Date());
        records.put(serviceEnum.getTableName(), date);
        Page page = new Page();
        page.setCurrent(1);
        page.setSize(singleSize > 0 ? singleSize : 1000);

        try {
            Class<? extends UDService> aClass = udService.getClass();
            Method method = aClass.getMethod(serviceEnum.getIntefaceName(), Page.class, String.class, String.class);
            IPage iPage = (IPage) method.invoke(udService, page, serviceEnum.getTableName(), date);


            if (!check(iPage, serviceEnum))
                return;

            remainingTasks(iPage.getPages(), serviceEnum);

        } catch (Exception e) {
            logger.error("任务上传失败", e);
        }
    }


    private void remainingTasks(long pages, ServiceEnum serviceEnum) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<Callable<Boolean>> callables = new ArrayList<>();
        int remainningPages = (int) pages - 1;
        int poolSize = remainningPages / singleBatchPages;
        poolSize = poolSize > 0 ? (poolSize + (remainningPages % singleBatchPages == 0 ? 0 : 1)) : 1;
        int pas;

        for (int pool = 1; pool <= poolSize; pool++) {
            if (poolSize == 1 || pool == poolSize) {
                pas = remainningPages;
            } else {
                pas = pool * singleBatchPages;
            }
            for (int currentPage = (pool - 1) * singleBatchPages + 1; currentPage <= pas; currentPage++) {
                final int i = currentPage + 1;
                Callable<Boolean> task = () -> {
                    Page page = new Page();
                    page.setCurrent(i);
                    page.setSize(singleSize > 0 ? singleSize : 1000);

                    Class<? extends UDService> aClass = udService.getClass();
                    Method method = aClass.getMethod(serviceEnum.getIntefaceName(), Page.class, String.class, String.class);
                    IPage iPage = (IPage) method.invoke(udService, page, serviceEnum.getTableName(), records.get(serviceEnum.getTableName()));

                    List records = iPage.getRecords();
                    if (records == null || records.size() < 1) {
                        return Boolean.TRUE;
                    }

                    String response = sendRecords(records, serviceEnum);
                    return parseResponse(response);
                };
                callables.add(task);
            }
            try {

                List<Future<Boolean>> futures = executorService.invokeAll(callables);
                for (Future<Boolean> future : futures) {
                    future.get();
                }
            } catch (Exception e) {
                logger.error(serviceEnum.getTableName() + ":任务执行期间出现问题", e);
                return;
            }

            callables.clear();
        }

        logger.info("上传任务执行成功：" + serviceEnum.getTableName());
        udService.insertDate(serviceEnum.getTableName(), records.get(serviceEnum.getTableName()));

    }

    private String sendRecords(List records, ServiceEnum serviceEnum) throws JAXBException {
        if (Objects.isNull(records) || records.size() < 1) {
            return null;
        }
        RequestEntity requestEntity = new RequestEntity();
        HeaderEntity headerEntity = new HeaderEntity();
        headerEntity.setReqUserId("PHMCHIS_PJ");
        headerEntity.setReqTraceNo(UUID.randomUUID().toString());
        headerEntity.setReqTime(NetDataUtil.date(new Date()));
        requestEntity.setHeader(headerEntity);
        requestEntity.setBody(records);

        StringWriter xmlWriter = new StringWriter();
        JAXBContext jaxbContext = JAXBUtils.createJAXBContext(RequestEntity.class);
        Marshaller marshaller = JAXBUtils.createMarshaller(jaxbContext);
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
        marshaller.marshal(requestEntity, xmlWriter);
        String xml = xmlWriter.toString();
        xml = JAXBUtils.replaceNameSpace(xml, null);

        logger.info("-发送-----------------------");
        logger.info(xml);

        return mchisInterface.callFun(authKey,
                serviceEnum.getServiceId(),
                serviceEnum.getOperationId(),
                xml);
    }


    private Boolean parseResponse(String response) {
        logger.info(response);
        if (StringUtils.isEmpty(response)) {
            return Boolean.TRUE;
        }
        if (response.contains("&lt;") && response.contains("&gt;")) {
            response = response.replaceAll("&lt;", "<")
                    .replaceAll("&gt;", ">");
        } else if (response.startsWith("<![CDATA[") && response.endsWith("]]>")) {
            response = response.replace("<![CDATA[", "").replace("]]>", "");
        }


        DocumentBuilder documentBuilder;
        StringReader stringReader = new StringReader(response);
        InputSource inputSource = new InputSource(stringReader);
        try {
            documentBuilder = JAXBUtils.getDocumentBuilder();
            Document document = documentBuilder.parse(inputSource);
            Element documentElement = document.getDocumentElement();


            Node resultcode = documentElement.getElementsByTagName("RESULTCODE").item(0);


            if (resultcode != null && resultcode.getTextContent().equals("1")) {
                return Boolean.TRUE;
            }

            Node resCode = documentElement.getElementsByTagName("ResCode").item(0);
            Node resMsg = documentElement.getElementsByTagName("ResMsg").item(0);
            logger.error("数据上传失败：\n[\n返回代码：" + resCode.getTextContent() + "\n返回消息：" + resMsg.getTextContent() + "\n]");

        } catch (Exception e) {
            logger.error("Response响应解析失败", e);
        }
        return Boolean.FALSE;
    }


    private boolean check(IPage iPage, ServiceEnum serviceEnum) throws JAXBException {

        if (iPage.getRecords() == null || iPage.getSize() < 1)
            return false;
        parseResponse(sendRecords(iPage.getRecords(), serviceEnum));
//        if (!parseResponse(sendRecords(iPage.getRecords(), serviceEnum)))
//            return false;

        return iPage.getPages() > 0;
    }


}
